/**
 ******************************************************************************
 * @file app_snake.h
 * @author GX (2524913364@qq.com)
 * @brief   贪吃蛇游戏，主要的界面分为两部分————游戏界面和操作界面
 * @version 1.0.0
 * @date 2022-05-26
 *
 * @copyright Copyright (c) 2022
 *
 ******************************************************************************
 *----------------------------------------------------------------------------*
 *  Remark         : Description                                              *
 *----------------------------------------------------------------------------*
 *  Change History :                                                          *
 *  <Date>     | <Version> | <Author>       | <Description>                   *
 *----------------------------------------------------------------------------*
 *  2022-05-26 | 1.0.0     | GX             | Create file                     *
 *----------------------------------------------------------------------------*
 *                                                                            *
 ******************************************************************************
 */

/*----------------------------- start of file -------------------------------*/

#ifndef _APP_SNAKE_H
#define _APP_SNAKE_H

/*-------------------------------- include ----------------------------------*/

#include <stdio.h>
#include <stdbool.h>
#include "app_snake_LinkList.h"


/*---------------------- Define parameters and types ------------------------*/

/* BGM路径----------------------------- */
#define SNAKE_BGM_PATH        "./data/bgm/snake_bgm1.mp3" 

/* 游戏记录文件的路径--------------------- */
#define SNAKE_RECODE_FILE_PATH  "./data/recode.txt"

/* 图片路径----------------------------- */
#define SNAKE_BODY_PATH       "./data/snake/body/"     /* 贪吃蛇的图片文件夹路径 */
#define SNAKE_WALL_PATH       "./data/snake/goods/wall.bmp"       /* 墙壁 */
#define SNAKE_GRASS1_PATH     "./data/snake/background/grass1.bmp"/* 草地1 */ 
#define SNAKE_GRASS2_PATH     "./data/snake/background/grass2.bmp"/* 草地1 */
#define SNAKE_GOODS_PATH      "./data/snake/goods/"         /* 物品的文件夹 */
#define SNAKE_FOOD_PATH       "./data/snake/goods/food.bmp"       /* 食物 */
#define SNAKE_POISON_PATH     "./data/snake/goods/poison.bmp"     /* 毒药 */
#define SNAKE_UP_PATH         "./data/snake/interface/up.bmp"     /* 上 */
#define SNAKE_DOWN_PATH       "./data/snake/interface/down.bmp"   /* 下 */
#define SNAKE_LEFT_PATH       "./data/snake/interface/left.bmp"   /* 左 */
#define SNAKE_RIGHT_PATH      "./data/snake/interface/right.bmp"  /* 右 */
#define SNAKE_BGMON_PATH      "./data/snake/interface/bgm_ON.bmp" /* bgm开 */
#define SNAKE_BGMOFF_PATH     "./data/snake/interface/bgm_OFF.bmp"/* bgm关 */
#define SNAKE_HEALTH_PATH     "./data/snake/interface/health.bmp" /* 生命 */
#define SNAKE_HEALTHOFF_PATH  "./data/snake/interface/health_off.bmp"/* 无生命 */
#define SNAKE_RUN_PATH        "./data/snake/interface/run.bmp"    /* 运行 */
#define SNAKE_SUSPEND_PATH    "./data/snake/interface/suspend.bmp"/* 暂停 */
#define SNAKE_BACK_PATH       "./data/snake/interface/back.bmp"   /* 返回 */


/**
 * @brief *******************游戏界面设计思路************************
 *  >> "视野":
 *  lcd的屏幕中取 480*480 来显示游戏界面，这个 480*480 的范围也就是 “视野”
 *    >（下面需要多次用到这个概念）<。
 *  地图的实际大小是视野的四倍即 960*960。随着蛇头的移动视野也会移动，直到视
 *  野移动到地图边界。
 * 
 *  >> “方块” 和 “区块”:
 *  将 960*960 的范围划分成 32*32 的许许多多的小格，这些小格称为 “方块”。
 *    >(跟方块相关的变量名会带有 “block” 或者 前缀 "b_")<
 *  将 960*960 分成四块(0~3) 480*480 ，每块称为 “区块”，区块内的哥哥方块同属
 *  一个区块。 >(跟区块相关的变量名会带有 “blockGroud” 或者 前缀 "bg_")<
 *  方块是物体的概念，比如：蛇头方块、蛇尾方块、食物方块、墙方块...方块里这些
 *  不同的物体也会有进一步的划分 @ref 。
 *  区块是游戏加载的单位，比如判断贪吃蛇是否吃到东西时，只会判断蛇头所在的区块
 *  范围内的物体，如此是为了能够不必每次都判断所有的物体，提高性能。注意：“蛇
 *  本身也是作为一个区块来看待，因此除了地图划分的四个区块以外还有第五个‘蛇区块’”。
 * 
 *  >> “方块坐标” 和 “实际坐标”
 *  整个地图被划分为很多个 “方块”，比如 960*960 的地图按照 32*32 划分成
 *  30*30 个方块，如此每个方块都有个自己的 “方块坐标”，x 和 y 坐标范围都是
 *  0～29一共三十个。而 “实际坐标” 就是lcd的坐标 480*800 的了。
 *  为了代码逻辑的简化，都是使用 “方块坐标” 作判断，到了显示的时候才换算成 
 *  “实际坐标”。
 *  而且方块坐标又可细分为，地图的方块坐标和视野的方块坐标。
 *  实际坐标也可细分为，地图的实际坐标和lcd的实际坐标。
 *  坐标间的换算后面会具体介绍，这里可以现有个概念。
 * 
 */
/* 游戏界面中相关的坐标定义----------------- */

/* 游戏界面的实际坐标 */
#define SNAKE_GAMEFACE_X_START  0
#define SNAKE_GAMEFACE_Y_START  0
#define SNAKE_GAMEFACE_WIDTH    480
#define SNAKE_GAMEFACE_HEIGHT   480
/* 游戏界面的方块坐标 */
#define SNAKE_GAMEFACE_B_X_START      0
#define SNAKE_GAMEFACE_B_Y_START      0
#define SNAKE_GAMEFACE_BLOCK_WIDTH    15
#define SNAKE_GAMEFACE_BLOCK_HEIGHT   15
#define SNAKE_GAMEFACE_B_X_END        (SNAKE_GAMEFACE_B_X_START + \
                                        SNAKE_GAMEFACE_BLOCK_WIDTH*SNAKE_BG_WIDTH_NUM)
#define SNAKE_GAMEFACE_B_Y_END        (SNAKE_GAMEFACE_B_Y_START + \
                                        SNAKE_GAMEFACE_BLOCK_HEIGHT*SNAKE_BG_HEIGHT_NUM)

/* 蛇头的方块坐标减去下面的两个值就能得到视野的起始方块坐标 */
#define SNAKE_GFACE_BLOCK_X     7
#define SNAKE_GFACE_BLOCK_Y     7

/* 地图的大小 */
#define SNAKE_MAP_WIDTH         960
#define SNAKE_MAP_HEIGHT        960

/* 方块大小(单位：像素) */
#define SNAKE_BLOCK_WIDTH       32
#define SNAKE_BLOCK_HEIGHT      32

/* 区块的大小(单位：方块) */
#define SNAKE_BG_WIDTH          15
#define SNAKE_BG_HEIGHT         15

/* 区块的数量 */
#define SNAKE_BG_WIDTH_NUM       2    /* 区块的横向数量 */
#define SNAKE_BG_HEIGHT_NUM      2    /* 区块的纵向数量 */

/**
 * @brief 贪吃蛇的游戏界面结构体。
 *    显示到屏幕的视野范围只是实际地图大小的四分之一，
 *    随着蛇头的移动视野也会不断移动
 */
typedef struct Snake_Iinterface
{
  int32_t b_width;            /* 地图的实际宽度 */
  int32_t b_height;           /* 地图的实际高度 */
  int32_t b_viewStart_x;      /* 视野起点的 x 坐标 */
  int32_t b_viewStart_y;      /* 视野起点的 y 坐标 */
  int32_t b_viewWidth;        /* 视野宽度 */
  int32_t b_viewHeight;       /* 视野高度 */
}Snake_Iinterface_t;

/**
 * @brief 方块类型的枚举定义（其命名时为了区分首字母加上蛇的单词首字母 “S”）
 *    按照蛇头碰到后是否会触发某些效果将方块分成 “可触发” 和 “不可触发”
 */
typedef enum
{
  /* 不可触发 */
  SNAKE_BACKGROUND = -1,      /* 背景 */
  /*--------------------*/
  TRIGGER_LINE = 0,           /* 触发分界线，上面的变量不可被触发，下面的变量可以 */
  /*--------------------*/
  /* 可触发 */
  SNAKE_HEAD,                 /* 蛇头 */
  SNAKE_BODY,                 /* 蛇身 */
  SNAKE_TAIL,                 /* 蛇尾 */
  SNAKE_FOOD,                 /* 食物 */
  SNAKE_POISON,               /* 毒药 */
  SNAKE_WALL                  /* 墙 */
}SBlockType_t;

/**
 * @brief 方块的触发效果
 */
typedef enum 
{
  /* 负面效果 */
  SNAKE_SHORTER = -10,        /* 变短 */
  SNAKE_LOSE_SCORE_5  = -5,   /* 失去分数 */
  SNAKE_LOSE_SCORE_3  = -3,   /* 失去分数 */
  SNAKE_LOSE_HEALTH_1 = -1,   /* 失去生命值 */
  /*--------------------*/
  SNAKE_NONE = 0,             /* 无效果 */
  /*--------------------*/
  /* 正面效果 */
  SNAKE_GET_HEALTH_1,         /* 加生命值 */
  SNAKE_GET_SCORE_2,          /* 加分数 */
  SNAKE_GET_SCORE_3,          /* 加分数 */
  SNAKE_GET_SCORE_4,          /* 加分数 */
  SNAKE_LONGER                /* 变长 */
}S_TriggerEffect_t;

/**
 * @brief 方块的属性之一 ———— 方向
 */
typedef enum
{
  SD_NONE,                    /* 无 */
  SD_UP,                      /* 上 */
  SD_DOWN,                    /* 下 */
  SD_LEFT,                    /* 左 */
  SD_RIGHT                    /* 右 */
}SDirection_t;


/* 操作界面中各个图标坐标范围--------------- */

/* 里面所有图片的长和宽 */
#define SNAKE_PIC_WIDTH       80
#define SNAKE_PIC_HEIGHT      80

/* 上、下、左、右 */
#define SNAKE_UP_X_START      600
#define SNAKE_UP_X_END        (SNAKE_UP_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_UP_Y_START      240
#define SNAKE_UP_Y_END        (SNAKE_UP_Y_START + SNAKE_PIC_HEIGHT)

#define SNAKE_DOWN_X_START    600
#define SNAKE_DOWN_X_END      (SNAKE_DOWN_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_DOWN_Y_START    400
#define SNAKE_DOWN_Y_END      (SNAKE_DOWN_Y_START + SNAKE_PIC_HEIGHT)

#define SNAKE_LEFT_X_START    520
#define SNAKE_LEFT_X_END      (SNAKE_LEFT_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_LEFT_Y_START    320
#define SNAKE_LEFT_Y_END      (SNAKE_LEFT_Y_START + SNAKE_PIC_HEIGHT)

#define SNAKE_RIGHT_X_START   680
#define SNAKE_RIGHT_X_END     (SNAKE_RIGHT_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_RIGHT_Y_START   320
#define SNAKE_RIGHT_Y_END     (SNAKE_RIGHT_Y_START + SNAKE_PIC_HEIGHT)

/* bgm开关 */
#define SNAKE_BGM_X_START     520
#define SNAKE_BGM_X_END       (SNAKE_BGM_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_BGM_Y_START     0
#define SNAKE_BGM_Y_END       (SNAKE_BGM_Y_START + SNAKE_PIC_WIDTH)  

/* 运行开关 */
#define SNAKE_RUN_X_START     600
#define SNAKE_RUN_X_END       (SNAKE_RUN_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_RUN_Y_START     0
#define SNAKE_RUN_Y_END       (SNAKE_RUN_Y_START + SNAKE_PIC_WIDTH) 

/* 返回键 */
#define SNAKE_BACK_X_START    680
#define SNAKE_BACK_X_END      (SNAKE_BACK_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_BACK_Y_START    0
#define SNAKE_BACK_Y_END      (SNAKE_BACK_Y_START + SNAKE_PIC_WIDTH)

// /* 方向指示图标 */
// #define SNAKE_DIRACTION_X_START 490
// #define SNAKE_DIRACTION_X_END   (SNAKE_DIRACTION_X_START + SNAKE_BLOCK_WIDTH)
// #define SNAKE_DIRACTION_Y_START 250
// #define SNAKE_DIRACTION_Y_END   (SNAKE_DIRACTION_Y_START + SNAKE_BLOCK_HEIGHT)

/* 生命值 */
#define SNAKE_HEALTH_X_START  520
#define SNAKE_HEALTH_Y_START  160

/* 分数 */
#define SNAKE_SCORE_X_START   520
#define SNAKE_SCORE_X_END     (SNAKE_SCORE_X_START + SNAKE_PIC_WIDTH)
#define SNAKE_SCORE_Y_START   80  
#define SNAKE_SCORE_Y_END     (SNAKE_SCORE_Y_START + SNAKE_PIC_WIDTH) 


/* 退出界面的相关定义---------------------- */
/* "SI"是 "snake interface" 的缩写 */
typedef enum
{
  SI_KEY_NONE,    
  SI_KEY_RESTART,
  SI_KEY_BACK,
  SI_KEY_EXIT
}SI_KEY;

/* 界面窗口 */
#define SI_WIDTH            288   /* 界面窗口宽度 */
#define SI_HEIGHT           320   /* 界面窗口高度 */
#define SI_X_START          256   /* 界面窗口的起始 x 坐标 ((LCD_WIDE-SI_WIDTH)>>1)*/
#define SI_Y_START          80    /* 界面窗口的起始 y 坐标 ((LCD_HEIGHT-SI_HEIGHT)>>1)*/
#define SI_COLOR            0x00E6E6E6/* 界面窗口颜色 */

/* 显示分数的位置 */
#define SI_SCORE_WIDTH      216   /* 分数的宽度 （9*24） */
#define SI_SCORE_X          292   /* ((SI_WIDTH-SI_SORE_WIDTH)/2 + SI_X_START) */
#define SI_SCORE_Y          112   /* (SI_Y_START+(32*1)) */

/* "restart" 按键 */
#define SI_RESTART_X_START  280
#define SI_RESTART_Y_START  176
#define SI_RESTART_WIDTH    240
#define SI_RESTART_HEIGHT   64
#define SI_RESTART_X_END    (SI_RESTART_X_START+SI_RESTART_WIDTH)
#define SI_RESTART_Y_END    (SI_RESTART_Y_START+SI_RESTART_HEIGHT)
#define SI_RESTART_COLOR    LCD_YELLOW
#define SI_RESTART_TEXT_X   316
#define SI_RESTART_TEXT_Y   192

/* "back" 按键 */
#define SI_BACK_X_START     280
#define SI_BACK_Y_START     240
#define SI_BACK_WIDTH       240
#define SI_BACK_HEIGHT      64
#define SI_BACK_X_END       (SI_BACK_X_START+SI_BACK_WIDTH)
#define SI_BACK_Y_END       (SI_BACK_Y_START+SI_BACK_HEIGHT)
#define SI_BACK_COLOR       LCD_CYAN
#define SI_BACK_TEXT_X      352
#define SI_BACK_TEXT_Y      256

/* "exit" 按键 */
#define SI_EXIT_X_START     280
#define SI_EXIT_Y_START     304
#define SI_EXIT_WIDTH       240
#define SI_EXIT_HEIGHT      64
#define SI_EXIT_X_END       (SI_EXIT_X_START+SI_EXIT_WIDTH)
#define SI_EXIT_Y_END       (SI_EXIT_Y_START+SI_EXIT_HEIGHT)
#define SI_EXIT_COLOR       LCD_PURPLE
#define SI_EXIT_TEXT_X      352
#define SI_EXIT_TEXT_Y      320

/* 玩家属性和游戏环境的相关定义------------ */

/**
 * @brief 键值定义
 */
typedef enum
{
  SNAKE_KEY_NONE,             /* 无操作 */
  SNAKE_KEY_UP,               /* 上 */
  SNAKE_KEY_DOWN,             /* 下 */
  SNAKE_KEY_LEFT,             /* 左 */
  SNAKE_KEY_RIGHT,            /* 右 */
  SNAKE_KEY_BGM,              /* BGM */
  SNAKE_KEY_SUSPEND,          /* 暂停/继续 */
  SNAKE_KEY_BACK              /* 返回 */
}SnakeKey_t;


/* 字体配置----------------------------- */
#define SNAKE_FONT            Font24x32     /* 字体大小 */
#define SNAKE_TEXT_COLOR      0x0000000     /* 字体颜色为黑色 */
#define SNAKE_BACK_COLOR      0x0000000     /* 不使用背景，颜色可以随便填 */
#define SNAKE_UNUSE_BACKCOLOR false         /* 不使用字体背景 */
#define SNAKE_TEXT_X          520           /* 文字的起始x坐标 */
#define SNAKE_TEXT_Y          104           /* 文字的起始y坐标 */




/*-------------------------- Function declaration ---------------------------*/

bool app_snake(void);

void show_all(datatype_t data);
bool eat_goods(datatype_t a, datatype_t s_head);
bool eat_snake(datatype_t a, datatype_t s_head);

#endif  /* _APP_SNAKE_H */
/*------------------------------ end of file --------------------------------*/
